﻿using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;

namespace SemanticEx.Tests
{
	[TestClass]
	public class IntegerRangeTests
	{
		[TestMethod]
		public void Can_produce_single_digit_ranges()
		{
			Assert.IsTrue(Regex.Match("0", Range1Digit(0, 9)).Success);
			Assert.IsTrue(Regex.Match("1", Range1Digit(0, 9)).Success);
			Assert.IsTrue(Regex.Match("2", Range1Digit(0, 9)).Success);
			Assert.IsTrue(Regex.Match("3", Range1Digit(0, 9)).Success);
			Assert.IsTrue(Regex.Match("4", Range1Digit(0, 9)).Success);
			Assert.IsTrue(Regex.Match("5", Range1Digit(0, 9)).Success);
			Assert.IsTrue(Regex.Match("6", Range1Digit(0, 9)).Success);
			Assert.IsTrue(Regex.Match("7", Range1Digit(0, 9)).Success);
			Assert.IsTrue(Regex.Match("8", Range1Digit(0, 9)).Success);
			Assert.IsTrue(Regex.Match("9", Range1Digit(0, 9)).Success);
			Assert.IsFalse(Regex.Match("10", Range1Digit(0, 9)).Success);
		}

		[TestMethod]
		public void Can_produce_double_digit_ranges()
		{
			Assert.IsTrue(Regex.Match("0", Range2Digit(0, 9)).Success);
			Assert.IsTrue(Regex.Match("1", Range2Digit(0, 9)).Success);
			Assert.IsTrue(Regex.Match("2", Range2Digit(0, 9)).Success);
			Assert.IsTrue(Regex.Match("3", Range2Digit(0, 9)).Success);
			Assert.IsTrue(Regex.Match("4", Range2Digit(0, 9)).Success);
			Assert.IsTrue(Regex.Match("5", Range2Digit(0, 9)).Success);
			Assert.IsTrue(Regex.Match("6", Range2Digit(0, 9)).Success);
			Assert.IsTrue(Regex.Match("7", Range2Digit(0, 9)).Success);
			Assert.IsTrue(Regex.Match("8", Range2Digit(0, 9)).Success);
			Assert.IsTrue(Regex.Match("9", Range2Digit(0, 9)).Success);
			Assert.IsFalse(Regex.Match("10", Range2Digit(0, 9)).Success);

			Assert.IsTrue(Regex.Match("4", Range2Digit(0, 10)).Success);
			Assert.IsTrue(Regex.Match("19", Range2Digit(12, 33)).Success);
			Assert.IsTrue(Regex.Match("51", Range2Digit(40, 69)).Success);
			Assert.IsTrue(Regex.Match("48", Range2Digit(42, 60)).Success);

			Assert.IsFalse(Regex.Match("11", Range2Digit(0, 10)).Success);
			Assert.IsFalse(Regex.Match("59", Range2Digit(12, 33)).Success);
			Assert.IsFalse(Regex.Match("33", Range2Digit(40, 69)).Success);
			Assert.IsFalse(Regex.Match("61", Range2Digit(42, 60)).Success);
		}

		[TestMethod]
		public void Can_produce_triple_digit_ranges()
		{
			Assert.Fail("Not implemented yet.");
		}

		[TestMethod]
		public void Can_produce_arbitrary_digit_ranges()
		{
			Assert.Fail("Not implemented yet.");
		}

		/// <summary>
		/// Single digit, from <paramref name="minValue"/> to <paramref name="maxValue" />.
		/// </summary>
		private string Range1Digit(int minValue, int maxValue)
		{
			//Require.Variable(() => minValue).IsInRange(0, 10);
			//Require.Variable(() => maxValue).IsInRange(0, 10);
			return string.Format(@"^[{0}-{1}]$", minValue, maxValue);
		}

		private string Range2Digit(int minValue, int maxValue)
		{
			//Require.Variable(() => minValue).IsInRange(0, 100);
			//Require.Variable(() => maxValue).IsInRange(0, 100);

			var minTens = minValue.SplitDigits().DefaultIfEmpty(0).LastOrDefault(); // get the tens digit
			var minOnes = minValue.SplitDigits().First(); // get the ones digit
			var maxTens = 0;
			var maxOnes = 0;
			if (maxValue.SplitDigits().Count() > 1)
			{
				maxTens = maxValue.SplitDigits().DefaultIfEmpty(0).Last(); // get the tens digit
				maxOnes = maxValue.SplitDigits().First(); // get the ones digit
			}

			var pieces = new List<string>();
			pieces.Add(string.Format("({0}[{1}-9])", (minTens == 0) ? minTens.ToString() + "?" : minTens.ToString(), minOnes));
			for (var tens = minTens + 1; tens < maxTens; tens++)
			{
				pieces.Add(string.Format("({0}[0-9])", tens));
			}
			pieces.Add(string.Format("({0}[0-{1}])", maxTens, maxOnes));
			var regex = string.Join("|", pieces.ToArray());
			return string.Format("^({0})$", regex);
		}
	}
}